package bjut.core.Message;

import bjut.core.extension.ExtensionLoader;
import bjut.core.constant.RpcConstant;
import bjut.core.enums.CompressTypeEnum;
import bjut.core.enums.SerializationTypeEnum;
import bjut.core.interfaces.Compress;
import bjut.core.interfaces.Serializer;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * * <p>
 * * custom protocol decoder
 * * <p>
 * * <pre>
 *  *   0     1     2     3     4        5     6     7     8         9          10      11     12  13  14   15 16
 *  *   +-----+-----+-----+-----+--------+----+----+----+------+-----------+-------+----- --+-----+-----+-------+
 *  *   |   magic   code        |version | full length         | messageType| codec|compress|    RequestId       |
 *  *   +-----------------------+--------+---------------------+-----------+-----------+-----------+------------+
 *  *   |                                                                                                       |
 *  *   |                                         body                                                          |
 *  *   |                                                                                                       |
 *  *   |                                        ... ...                                                        |
 *  *   +-------------------------------------------------------------------------------------------------------+
 *  * 4B  magic code（魔法数）   1B version（版本）   4B full length（消息长度）    1B messageType（消息类型）
 *  * 1B compress（压缩类型） 1B codec（序列化类型）    4B  requestId（请求的Id）
 *  * body（object类型数据）
 *  * </pre>
 *
 * @Author: zhuzhiming
 * @Date: 2022/4/8 20:53
 */
public class RpcMessageEncoder extends MessageToByteEncoder<RpcMessage> {

    private static final AtomicInteger REQUEST_ID = new AtomicInteger(0);

    @Override
    protected void encode(ChannelHandlerContext context, RpcMessage rpcMessage, ByteBuf byteBuf) throws Exception {

        try {
            byteBuf.writeBytes(RpcConstant.MAGIC_NUMBER);
            byteBuf.writeByte(RpcConstant.VERSION);
            byteBuf.writerIndex(byteBuf.writerIndex() + 4);
            byteBuf.writeByte(rpcMessage.getMessageType());
            byteBuf.writeByte(rpcMessage.getCodec());
            byteBuf.writeByte(CompressTypeEnum.GZIP.getCode());
            byteBuf.writeInt(REQUEST_ID.getAndIncrement());

            byte[] bodyBytes = null;
            int fullLength = RpcConstant.HEAD_LENGTH;

            if (rpcMessage.getMessageType() != RpcConstant.HEART_REQUEST_TYPE && rpcMessage.getMessageType() != RpcConstant.HEART_RESPONSE_TYPE) {

                String serialType = SerializationTypeEnum.getSerialType(rpcMessage.getCodec());
                Serializer serializer = ExtensionLoader.getExtensionLoader(Serializer.class).getExtension(serialType);
                byte[] dataBytes = serializer.serialize(rpcMessage.getData());

                String compressType = CompressTypeEnum.getCompressType(rpcMessage.getCompress());
                Compress compress = ExtensionLoader.getExtensionLoader(Compress.class).getExtension(compressType);
                bodyBytes = compress.compress(dataBytes);

                fullLength += bodyBytes.length;
            }

            if (bodyBytes != null) {
                byteBuf.writeBytes(bodyBytes);
            }
            // 记录最终写的位置
            int writerIndex = byteBuf.writerIndex();
            byteBuf.writerIndex(writerIndex - fullLength + RpcConstant.MAGIC_NUMBER.length + RpcConstant.VERSION);
            byteBuf.writeInt(fullLength);
            byteBuf.writerIndex(writerIndex);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
